:Introduction

قم بداية بوضع CD فرقة GODSMACK وقم بالاستماع الى اغنية 'Release the demons'

هذه النسخة هي ترجمة عن النسخة الانكليزية التي كتبتها بالاصل لـ Fusion وبالطبع اذكر دوما بان المعلومات المترجمة قد لا توصل بالضرورة الفكرة كاملة لان المصطلحات جميعها اجنبية لذا من الافضل مراجعة النسخة الانكليزية من هذا المقال..

بالنسبة للموضوع الذي سنتناوله فهناك الكثير من المقالات الموجودة على مواقع الويب، لسوء الحظ فان القليل منهم من يعطي معلومات واضحة وكاملة حول جدول الموارد Imports Table وبنية الملف التنفيذي PE format.. واحدة من افضل المقالات التي قراتها حول هذا الموضوع كانت بقلم Eduardo Labir المعروف بـ hav0k وكانت هي المقالة التي توفرت بين يدي واستطعت فهمها بالكامل فشكرا له.

في هذا المقال على خلاف مقالات كثيرة قبله سنتناول احد جوانب الهندسة العكسية Reverse Engineering اذ اننا سنقوم بالتعديل على جدول الموارد لاضافة وظائف جديدة للملف التنفيذي دون استخدام برامج تقوم بهذا العمل، سنقوم ايضا بالتعديل على الـ resource الخاصة بالملف الهدف ونهاية سنقوم بتصحيح واعادة كتابة جزء من رماز البرنامج لجعله يعمل بشكل كامل.. الملف الهدف الذي سنتناوله هو برنامج كتبه اخي CuTedEviL لمجموعة C.O.D.E التي توقفت حاليا عن العمل للعديد من الاسباب.

قمت بتضمين البرنامج في هذه الحزمة المضغوطة 'Mission #1.zip' لكن قبل ان تقوم بتشغيل الملف التنفيذي الرجاء التاكد من ان توقيع الـ MD5 الخاص بالملف هو '1B084265DC03B55ACA944A7B3C2F290E' لتضمن بان الملف لم يتم التلاعب به من اي شخص.. حتى انا (:{ (فكر بالموضوع ;)، قم ايضا بقراءة التعليمات الموضحة في ملف الـ .doc المرفق من قبل CuTedEviL لتتكون لديك فكرة واضحة عن العمل الذي سنقوم به.

حسنا, يمكنني الان افتراض بانك قرات جميع السطور السابقة وفهمت جيدا من سنقوم به وتريد المتابعة.. لنقم اذا بالحصول على البرامج المطلوبة وقم بالاستعداد لاحدى المقالات المميزة D:

بالمناسبة، قمت بكتابة مقال منذ فترة شبه طويلة حول اعادة كتابة جدول الموارد واضافة وظائف جديدة للملف التنفيذي يدوياً يفضل ان تقوم بمراجعتها لان هذا المقال لن يتناول التفاصيل الدقيقة مجددا بالنسبة لهذا الموضوع.


:Tools we'll use

- LordPE، او اي محرر ست عشري.

- OllyDbg، او اي منقح (يفضل ان يكون ذو واجهة مرئية).

- فقط!


?What is the Import Table, anyhow

جدول الموارد برأيي هو المكان الذي يقوم فيه المترجم compiler بتخزين المعلومات الخاصة بكل وظيفة من الوظائف التي يقوم البرنامج باستخدامها. يتالف جدول الـ IT (Import Table) من جدول RVAs (Relative Virtual Address) تشير الى ما يسمى بالـ IMAGE_IMPORT_DISCRIPTOR (وبالعربي يطلق عليه حسبما اذكر، صورة واصف جدول الموارد.. اشير هنا الى ان كلمة IMAGE تطلق على المصطلحات التي يتم التعامل معها في الذاكرة) حيث يوجد IID (سنطلق عليه هذا الاختصار لتسهيل الكتابة!) لكل ملف DLL يتم استخدامه في البرنامج، كما ويتالف من جدول يحوي اصفاراً فقط والذي يشير الى نهاية الـ IT.

تتالف بنية الـ IID من المتحولات التالية

IMAGE_IMPORT_DESCRIPTOR struct
	OriginalFirstThunk	dd  0 ; RVA to original unbound IAT (ImportAddressTable) 
				      ; < table of RVAs to functions names
	TimeDateStamp		dd  0 ; usually not used
	ForwarderChain		dd  0 ; usually not used
	Name			dd  0 ; RVA to DLL name
	FirstThunk		dd  0 ; RVA to IAT array < table of doors to the func.
IMAGE_IMPORT_DESCRIPTOR ends
دعونا ناخذ الملف الهدف لفهم هذا الموضوع بالصورة الجيدة، لذا قم باستخدام LordPE لفتح الملف وانقر على Directories ثم انقر L بجانب ImportTable وانظر الى اول ملف DLL مستخدم user32.dll، سيبدو الـ IID الخاص به بالشكل التالي:
ImageImportDescriptor:
    OriginalFirstThunk:  0x00002108
    TimeDateStamp:       0x00000000  (GMT: Thu Jan 01 00:00:00 1970)
    ForwarderChain:      0x00000000
    Name:                0x0000221C  ("user32.dll")
    FirstThunk:          0x00002018
يقوم الـ OriginalFirstThunk بحمل قيم الـ RVAs الخاصة بجدول الوظائف المستخدمة، تاكد من هذا فالعنوان 2108 سيحمل القيم التالية:
xx xx xx xx xx xx xx xx 9A 21 00 00 A8 21 00 00
B4 21 00 00 C6 21 00 00 8C 21 00 00 EA 21 00 00
F8 21 00 00 0C 22 00 00 78 21 00 00 68 21 00 00
40 21 00 00 56 21 00 00 DA 21 00 00 00 00 00 00
ولان الـ OFT (OriginalFirstThunk) يحمل الـ RVAs الخاصة باسماء الوظائف المستوردة لذا فان تناولت العنوان 219a على سبيل المثال الذي يظهر بلون ابيض في الترميز السابق ستجد التالي:
80 01 4C 6F 61 64 43 75 72 73 6F 72 41 00
والذي يمثل وظيفة LoadCursorA..

حسنا، الان بالنسبة لـ TimeDateStamp و ForwarderChain نادرا ما يتم ملؤها بمعلومات ويقوم بهذا المترجم المستخدم وبالتالي لا تهم القيمة التي يملكونها. الان ناتي الى الـ Name حيث يملك قيمة الـ RVA الذي يشير الى اسم ملف الـ DLL المستخدم.. نهاية لدينا الـ FirstThunk والذي يملك قيمة RVA تشير الى جدول يتم ملؤه من قبل المترجم بعناوين الوظائف المستخدمة وبالتالي فان العنوان 2018 سيحوي الترميز التالي:

xx xx xx xx xx xx xx xx 9A 21 00 00 A8 21 00 00
B4 21 00 00 C6 21 00 00 8C 21 00 00 EA 21 00 00
F8 21 00 00 0C 22 00 00 78 21 00 00 68 21 00 00
40 21 00 00 56 21 00 00 DA 21 00 00 00 00 00 00
لحظة.. كما ترى فان الترميز الخاص بالـ FT (FirstThunk) مشابه للترميز الخاص بالـ OFT فكيف حدث هذا؟ لا اريد ان اعقد الامور اذ استطيع ان اقوم بان الـ FT يستخدم لاستدعاء الوظيفة في حال كان الـ OFT يحوي معلومات خاطئة وفي حال كان الـ FT والـ OFT يحوي معلومات خاطئة فان البرنامج يظهر خطا يغلقه عند التشغيل..

بالطبع فهذا الامر لا يكون صحيحا في برامج اخرى فان اخذت المفكرة على سبيل المثال (الاصدار الخاص بـ winXP) وتفحصت الـ IID الخاص بملفات الـ DLL المستخدمة لوجدت بان الـ OFT يشير الى جدول الى RVAs الخاصة باسماء الوظائف المستخدمة بينما يشير الـ FT الى عناوين مثل '08 1E 3D 76' اي العنوان '763d1e08' والذي يمثل العنوان المطلق لوظيفة PageSetupDlgW


?So what do we need to have IT working

1- الـ RVA وال SIZE الخاص بالـ IT يجب ان يكون صحيحا.

2- الـ IT يجب ان يتم انهاؤه بجدول (او يمكن ان تسمى ترويسة) تشير الى نهايته.

3- الـ FT على الاقل يجب ان يحوي معلومات صحيحة لكل ملف DLL مستخدم.


?Fine, and what func. we will import

لاننا سنقوم باستدعاء الوظائف الجديدة المطلوبة بشكل يدوي (فقد) نحتاج الى الكثير منهم (مفترضين هذا الامر), لذا دعونا ننظر الى هذا الامر من زاوية اخرى، لم نقوم باستدعاء الكثير من التعليمات وتعديل الكثير في الترميز بينما لا نحتاج الا الى وظيفتين على الاقل في البرنامج يمكن بواستطهما استدعاء اي وظيفة اخرى نرغب بها عند الحاجة ودون الحاجة الى اعادة التعديل مجددا، هاتان الوظيفتان هما LoadLibraryA التي تستخدم للحصول على مقبض لملف DLL معين ووظيفة GetProcAddress التي تستخدم للحصول على العنوان الخاص بوظيفة معينة من ذلك الملف.


سنقوم في البداية باستدعاء وظيفة LoadLibraryA والموجودة في ملف kernel32.dll، هذا يمكن ان يتم باحدى طريقتين.. الاولى بانشاء IID جديد لهذه المكتبة لاستدعاء الوظيفة المذكورة اما الطريقة الثانية فهي باستدعاء الوظيفة بالاعتماد على جدول الـ IID الاصلي الموجود في الملف لهذه المكتبة kernel32.dll.. بالطبع فان لكل طريقة محاسن ومساؤى لكن المشكلة المشتركة بينهما هي اننا نحتاج الى التركيز لايجاد مساحة اضافية للتعديلات التي سنقوم بها.. لذا دعونا نختار الطريقة الاسهل بمقارنة المحاسن والمساؤى..

الطريقة الاولى كما ذكرت تتم باضافة IID جديد الى الـ IT، هذا يعني اننا نحتاج الى مساحة غير مستخدمة تلي الـ IT لنقوم باضافة معلومات الـ IID الجديد اليه.. دعونا نتفحص هذا الامر..

الـ IT يبدا عند العنوان 20a0 فان تفقدت هذا العنوان لوجدت باننا لو اردنا ان نقوم بتمديد (زيادة حجم الـ IT) لاضافة الـ RVA الخاص بالـ IID الجديد لاحتجنا الى مزيد من المساحة التي لا تتوفر لنا.. كما تظهر الصورة



الطريقة الثانية تتم باضافة معلومات الوظيفة المطلوبة الى الـ IID الاصلي الخاص بملف kernel32.dll، المشكلة هنا، مجددا، اننا لا نملك مساحة كافية بعد جدول الـ RVAs كما تظهر الصورة التالية حيث يبدو جدول الـ RVAs المشار اليه من قبل الـ FT



الفكرة المشتركة للحل في الطريقتين هي اننا سنضطر الى نقل اما الـ IT الى مكان جديد واصلاح العنوان والحجم الناتج عن التغيير او اننا سنضطر الى نقل الـ RVAs المشار اليها من قبل الـ FT واصلاح العنوان واضافة RVAs جديدة تشير الى الوظائف المطلوبة.. بالنسبة لي فاني ساقوم باختيار الطريقة الاولى!


:Bust a Move

ساقوم في هذه الفقرة بوضع الخطوات اللازم تنفيذها لاستيراد الوظائف المطلوبة..

1- ايجاد cave مناسب.

2- نقل الـ IT القديم اليه وقبل اغلاقه..

3- اضافة الـ RVA الخاصة بالـ IID الجديد ومن ثم اغلاقه.

4- اضافة معلومات الـ IID الخاص بـ kernel32.LoadLibraryA و kernel32.GetProcAddress

5- تصحيح معلومات الـ RVA والـ SIZE الخاص بالـ IT في معلومات الـ PE

6- اختبار واصلاح جميع الاخطاء التي سهونا عنها.


حجم الـ cave الذي نبحث عنه يجب على الاقل ان يكون 100 بايت (64h) والسبب [حجم الـ IT القديم = 80 بايت (50h) + الـ IID الجديد (4 بايت * 5 مقاطع //OFT-TDS-FCH-FT//) = 20 بايت -> 100 بايت اجمالا]، ساقوم باختيار العنوان 22c0 الموجود في المقطع .rdata

الان في الـ IID الذي سنضيفه سنحتاج الى اسماء الوظائف المطلوبة وبالتالي يجب اضافتهم الى الملف، لا يوجد مشكلة.. سنقوم باضافة اسماء الوظائف في العنوان 2294 والتي ستبدو بالشكل التالي



كما تعلم (او اصبحت تعلم!) فان بنية كل وظيفة هي التالي (ordinal / hint / name / end_byte) لهذا فقد قمت بكتابة (00 00 LoadLibraryA 00)، حيث يمكن استدعاء الوظيفة باستخدام الـ ordinal او الاسم وبما اننا اعتمدنا الاسم فنقوم باسناد القيمة 00 الى الـ ordinal والـ hint وقمنا بوضع 00 بعد اسم الوظيفة لانهاءه.. الان سنقوم بنقل واعادة كتابة الـ IT في العنوان 22c0 والتي ستبدو على الشكل التالي



كما تلاحظ في الصورة السابقة فقد جعلت قيمة الـ OFT مساوية للـ FT بالقيمة 2330 (30 23) حيث ساقوم بوضع قيم الـ RVAs الخاصة بالـ FT والتي تشير الى الوظائف المطلوبة.

الصورة التالية تظهر الخطوات النهائية..



في النهاية، دعونا نقوم باصلاح الـ RVA والـ SIZE الخاص بالـ IT لذا قم باستخدام LordPE بتغيير الـ RVA القديم الخاص بالـ IT من 20a0 الى 22c0 والـ SIZE من 50 الى 64 وقم بنقر زر Save.. (يمكنك الان البدء بالدعاء!), قم الان بالنقر على L.. ان سار كل شئ على ما يرام فانك يجب ان ترى الـ IID الجديد الخاص بـ kernel32.dll في نهاية النافذة.. شئ من هذا القبيل..



فان لم تبدو الـ IT لديك بهذا الشكل او ان LordPE يظهر خطا ما فبديهيا قمت بتنفيذ شئ ما بشكل خاطئ! عد وقم بالتاكد من كل بايت قمت بتغييره.. (الان تعلم لم افضل استدعاء هاتين الوظيفتين على الاقل وترك الباقي عند الحاجة.. اضطررت في بداياتي الى اعادة كتابة بضع المئات من البايتات، تسجيل ملاحظات، نقل، اختبار، تصحيح و -fscking all the time- D;)


!Welcome to next level, REsourcing some

في هذه المرحلة سنقوم باضافة زر يحمل العنوان Show الى الملف التنفيذي بدون استخدام اي برنامج.. لا تعتقد بان اعادة بناء الـ IT كان امرا معقدا.. ستقوم بتغيير رايك في ثوان p:

تحتاج هنا الى فهم ما يدعى بالـ IMAGE_RESOURCE_DIRECTORY والتي سنطلق عليها من الان IRD.

تعلم بان المترجمات تقوم بوضع الـ resource المستخدمة في البرنامج في المقطع المسمى .rsrc حيث يحوي هذا المقطع معلومات تستخدم لاظهار الازرار, القوائم, المناطق النصية الخ الخ.. كل resource يتالف من عدة IRDs وكل IRD قد يشير الى IRD ثانوي او الى ما يسمى بالـ IMAGE_RESOURCE_DIRECTORY_ENTRY الذي يشير الى بداية جدول المعلومات الخاصة بنوع معين من العناصر المضمنة في الـ resource مثل الازرار الخ والذي سنطلق عليه من الان IRDE.

تتكون بنية الـ IRD من المعلومات التالية

IMAGE_RESOURCE_DIRECTORY struct
	DWORD	Characterstics
	DWORD	TimeDateStamp
	WORD	MajorVersion
	WORD	MinorVersion
	WORD	NumberOfNamedEntries
	WORD	NumberOfIdEntries
IMAGE_RESOURCE_DIRECTORY ends
وبالتالي ترى بان كل IRD يتالف من 16 بايت, بالنسبة (لنا؟) الـ reversers, لا يهمنا الـ IRD بقدر ما يتهمنا معرفة بداية المعلومات الخاصة بالعنصر المطلوب، لذا فاننا نقوم بتخطي 16 بايت (حيث ان الـ IRD الرئيسي الاول يحوي معلومات حول الـ IRDs الثانوية) وسنكون امام اول IRDE والذي يتالف من 8 بايتات و تتكون بنيته من المعلومات التالية
IMAGE_RESOURCE_DIRECTORY_ENTRY struct
	DWORD	Name
	DWORD	OffsetToData
IMAGE_RESOURCE_DIRECTORY_ENTRY ends
غالبا ما ياتي ترتيب الـ IRDE ليصف العناصر التالية بالترتيب الموضح: الايقونات, القوائم, النوافذ, الخ..

في مثالنا، الـ RVA الخاص بالـ .rsrc هو 4000، ان انتقلت الى ذلك العنوان ستكون عند الـ IRD الرئيسي والذي يبدو بالشكل

00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00
كما ترى فان NumberOfIdEntries هو 5 اي لدينا 5 IRDEs كل واحد يقدم معلومات حول موضوع معين.. لنتخطى 16 بايت لنصل الى بداية الـ IRDEs والذي يبدو بالشكل
03 00 00 00 38 00 00 80 04 00 00 00 50 00 00 80
05 00 00 00 68 00 00 80 0E 00 00 00 80 00 00 80
كما ذكرت في توضيح بنية الـ IRDE فانه يتالف من 8 بايتات، اول 8 بايتات تظهر في الترميز السابق خاصة بالايقونات، لنتخطاهم لنصل الى 8 بايتات اخرى تمثل القوائم، نتخطاهم فنصل الى البايتات الخاصة بالنوافذ وهذا ما يهمنا.. هذه البايتات هي
05 00 00 00 68 00 00 80
ما يهمنا من هذه البايتات هو الـ 4 الاخيرة وهي '68 00 00 80'، ان كان البايت ذو الترتيب الاعلى يحمل القيمة 80 فان البايتات تشير الى ازاحة IRD ثانوي والذي في مثالنا موجود في الازاحة 0068 اي ان قيمة الـ RVA = '4000 + 0068 = 4068' لذا توجه الى هناك..

مجددا، تخطى 16 بايت وستكون امام

E8 03 00 00 E0 00 00 80
البايت ذو الترتيب الاعلى هو 80 وبالتالي فان 00e0 يمثل ازاحة الـ IRD الثانوي الثاني لذا توجه الى العنوان 40e0 وتخطى 16 بايت وستجد
09 04 00 00 48 01 00 00
البايت ذو الترتيب الاعلى يحمل القيمة 00 وبالتالي فان الازاحة تمثل بداية الـ IMAGE_RESOURCE_DATA_ENTRY والتي سنطلق عليها IRDAE والتي تحمل معلومات خاصة بالنوافذ والتي كنا نبحث عنها..

توجه الى 4148 وستجد معلومات الـ IRDAE والذي تمثل بنيته بالشكل

IMAGE_RESOURCE_DATA_ENTRY struct
	DWORD	OffsetToData
	DWORD	Size
	DWORD	CodePage
	DWORD	Reserved
IMAGE_RESOURCE_DATA_ENTRY ends
حيث ستكون امام البايتات التالية
00 42 00 00 4A 01 00 00 00 00 00 00 00 00 00 00
وبالتالي من تمثيل البنية تجد بان الـ RVA (وليست قيمة الازاحة) الى المعلومات المطلوبة هو 4200 وحجم هذه البيانات 14a..

احاول ان اجعل هذا المقال بابسط واقصر صورة ممكنة واجعا نصب عيني شرح كل ما يخطر في بالي.. لا اريد ان اجعلك تنفجر وانا احاول شرح بنية الـ dialog، اعتقد بانه بامكانك فهمها بنفسك.. قم بابحاثك الخاصة وستصل الى معلومات لم تعتقد بانك قد تصل اليها من قبل وتذكر قول +Fravia "Links die, Searching doesn't"..


:Structure of a button

سنقوم الان باضافة زر الى النافذة الخاصة بالبرنامج الهدف فكيف يمكن القيام بهذا؟ والسؤال الذي يخطر في بالي دوما.. هل نملك مساحة كافية؟؟

بداية، دعوني ابين لكم بنية اي زر, الرجاء الانتباه الى اني اكتب البنية ليس بالاعتماد على مصادر خاصة وانما حسبما توصلت اليه ابحاثي التي يبدو انها لم تكن مثمرة جدا p: لذا اتمنى الا يكون هناك اختلاف كبير مع البنية الاصلية..

Button struct
	DWORD	??????	; I don't know what is it for
			; lpWindowName? or lpClass!? (help :[)
	DWORD	ExStyle
	DWORD	Style
	WORD	LeftPos
	WORD	TopPos
	WORD	Width
	WORD	Height
	DWORD	ID
	WORD	HelpID
	WORD	??????	; I'm not sure of this too
			; I know it's not TabOrder thing
			; for buttons it's "80 00" always, so is it lpClass?
	DD	Caption
Button ends
بالطبع، كما في اي resource فبنية الزر يجب ان تنتهي بكلمة تتالف من اصفار تشير الى نهاية البنية. الان لاضافة الزر Show المطلوب نحتاج الى (؟؟؟: 4بايتات + exstyle: 4بايتات + style: 4بايتات + left: 2بايتات + top: 2بايتات + width: 2بايتات + height: 2بايتات + ID: 4بايتات + helpid: 2بايتات + ؟؟؟: 2بايتات + caption: 8بايتات //S.h.o.w// + closing: 4بايتات) = 40 بايت لكننا لا نملك هذا المقدار من المساحة بعد الـ IRDAE فما العمل؟ لن ابحث في موضوع نقل الـ IRDAE ايضا بل ساقوم باستغلال بعض البيانات التي اجدها غير ضرورية في البرنامج مثل ' - Written for [C.O.D.E] ' وساقوم بالغاء كل ما لا نحتاج اليه من بايتات متبقية وبالتالي سيبدو الـ IRDAE الجديد بالشكل



في الواقع, بعد ان تقوم باختبار التغييرات التي قمت بها ستلاحظ بان الـ label بالكامل قد اختفى.. لا اعلم حقا ما السبب حيث اني لم اغير شيئا في بنيته سوى اني استعرت بعض بايتاته.. باي حال الامر غير مهم الى هذه الدرجة وان كنت تعلم السبب ارجو مراسلتي به.

باي حال, فان الملف يعمل بشكل جيد وقد (قمنا؟) بنجاح باضافة الزر المطلوب لذا تهانينا..


:Introduction to REngineering

ناتي الان الى القسم المتعلق بالـ code injection حيث سنقوم باضافة ترميز الى البرنامج لجعل زري Show و Exit يعملان كما كان المبرمج قد خطط. لمتابعة هذا المقال تحتاج معلومات حول البرمجة بالاسمبلي والى فهم وظائف API وبالطبع تحتاج الى معرفة الطريقة السليمة لاضافة الترميز الخاص بك الى برنامج ما.


:Understanding the code flow

قم بتحميل الملف في Olly، الان قم بالنقر بالزر الايمن للماوس واختر Search for -> All intermodular calls، شكرا لله فلا يوجد الكثير من الوظائف المستوردة والتي يجب الاهتمام بها, كما ارى من الوظائف الموجودة فان وظيفة CreateDialogParamA هي ما يجب الاهتمام به لذا دعونا نقرا القليل حول استخدامها، قم بالبحث عن الوظيفة في مرجع الـ win32api الخاص بك وستجد المعلومات التالية
The CreateDialogParam function creates a modeless dialog box from a dialog box 
template resource. Before displaying the dialog box, the function passes an 
application-defined value to the dialog box procedure as the lParam parameter 
of the the WM_INITDIALOG message. An application can use this value to initialize 
dialog box controls. 

HWND CreateDialogParam(

    HINSTANCE hInstance,	// handle to application instance
    LPCTSTR lpTemplateName,	// identifies dialog box template
    HWND hWndParent,		// handle to owner window
    DLGPROC lpDialogFunc,	// pointer to dialog box procedure  
    LPARAM dwInitParam 		// initialization value
   );
ان قرات النص المعلّم باللون الابيض ستجد بان بارامتر lpDialogFunc يقوم بمعالجة الاوامر (الرسائل) المرسلة الى عنصر النافذة، في Olly يمكنك مشاهدة بانه موجود في العنوان 401103

بعد ان يقوم البرنامج بمعالجة جميع تلك الرسائل التي ترسل عبر امر WM_INITDIALOG الخاص بتهيئة النافذة فانه يقوم بانتظار الرسائل المرسلة الى العناصر من مختلف الاوامر الاخرى والتي يتم معالجتها ايضا عبر بارامتر lpDialogFunc..

CuTedEviL كان محقا, فالمبرمج كان مستهترا ولم يقم بربط الزر Exit بالاوامر الخاصة به فكيف نقوم بذلك عوضا عنه؟ الطريقة لعمل ذلك هي بفهم عمل lpDialogFunc وكيف يتم معالجة الرسائل..

المشكلة التي لدينا هنا هي اننا نملك زرين لذا يجب على البرنامج ان يقوم بالتمييز بينهما لتنفيذ الترميز الخاص بكل واحد.. لفهم هذا الامر بشكل جيد قمت بكتابة تطبيق بسيط يحوي على 3 ازرار ومن ثم قمت بتنقيحه لفهم الموضوع حسب الاختلافات بين التطبيقين.. التطبيق مع الشفرة المصدرية مضمن في المجلد testme لكن قبل ان تقوم بتنفيذ الملف تاكد من توقيع الـ MD5 الخاص به "BE75C2DAC0DA27F5F5A0DA296418B6D6").

قم بتحميل البرنامج في Olly وقم بتشغيله بواسطة F9, وقبل ان تقوم بالنقر على اي زر قم بوضع نقطة توقف على العنوان 401051، على هذا العنوان كي نضمن بان البرنامج قد تلقى امر WM_COMMAND خاص باحد الازرار.. الان قم بالنقر على زر Show وسترى التالي



سيقوم الان البرنامج بالتمييز بين الازرار الثلاث, يقوم البرنامج باستخدام بارامتر wParam الذي يتم استرجاع قيمته من قبل الـ dialog للتمييز بين الازرار والذي سيحمل القيمة الخاصة بالـ ID التابعة للزر.. كما ترى في الصورة السابقة فناك امر CMP AX, 12C.. القيمة الست عشرية 12C تساوي 300 عشريا اي ان البرنامج يتحقق من كون الزر هو Show والذي تملك الـ ID الخاصة به القيمة 300، ولانك قمت بالنقر على هذا الزر فان البرنامج ستجاهل امر الـ JNZ وسيقوم باظهار الرسالة الخاصة به على الشاشة



قم باختبار الازرار الاخرى لتفهم الموضوع بشكل اعمق. الان كيف يمكننا استغلال هذه المعلومات مع البرنامج الهدف؟

دعونا بداية نقوم باخذ ملاحظات حول قيمة الـ IDs الخاصة بكل عنصر في النافذة.. Exit: 1001, Show: 1004, textbox: 1002 - قم الان بتحميل البرنامج في Olly, انقر F9 لتشغيله وقم بالنزول في Olly حتى تصل الى عنوان التحقق من امر WM_COMMAND وهو 40111b، قم بوضع نقطة توقف على العنوان 401122 لتضمن بان البرنامج تلقى ذلك الامر، لنقم الان بتطبيق ما تعلمناه ولنقم بالنقر على زر Exit.. هذا ما سيظهر في Olly



يقوم الامر MOV EAX, DWORD PTR [EBP+10] بنسخ قيمة الـ wParam الخاص بالزر الى EAX, بعدها يتم مقارنة القيمة الموجودة في EAX مع 2711 والتي تساوي 10001 في النظام العشاري, تلاحظ ايضا بانه يوجد تعليمة SendMessageA مع الامر WM_CLOSE تلي امر التحقق يتم تنفيذها في حال التطابق لذا لاصلاح الزر Exit يكفي تغيير القيمة 2711 الى الـ ID الخاصة به والتي تساوي 3E9 ست عشريا.. نعم, اعلم, لم انس ان هناك زر Show ايضا فماذا يجب ان نعمل لاضافة ترميز متوافق معه؟ هذه هي الخطوات


1- تحويل الفيض الى مكان اخر

2- اضافة الترميز المطلوب لتنفيذه

3- اعادة الفيض الى المسار الطبيعي


!Cave sweet Cave

سنقوم باختيار العنوان 402340 من اجل الـ cave المطلوب, الان يجب ان تقوم بتغيير مسار الفيض الى ذلك الـ cave, شكرا لـ CuTedEviL من اجل البايتات الخمس التي تركها لنا من اجل الـ JMP, ادين لك بواحدة (:

سنقوم باستبدال الامر AND الذي تراه في الصورة السابقة بـ JMP الى العنوان الذي اخترناه, لذا قم باستبدال AND EAX, 0FFFF بـ JMP 402340 وانقر enter عليه للانتقال الى ذلك العنوان.

الان سنقوم بادخال ترميز يتحقق من الزر المضغوط.. ولان البرنامج قام بنقل قيمة wParam الى EAX سلفا لذا سنقوم بادخال تعليمة CMP في بداية الترميز لتفحص نوع الزر ان كان Show.. قبل هذا يجب ان تعلم باننا نحتاج الى وظيفتي GetDlgItemTextA لاسترجاع محتويات الـ textbox والى MessageBoxA لاظهار ما تم استرجاعه.. اي اننا نحتاج الى اسمي هاتين الوظيفتين في البرنامج، لا باس يمكن القيام بهذا التعديل بواسطة LordPE في عنوان ما تختاره ويظهر التعديل في الصورة التالية



الان الترميز الذي نحن بحاجة لادخاله هو..

	cmp	eax, 3ec		; compare the ID with 3EC = 'Show'
	jne	40112a			; it's not so go back to normal flow
; now the 'Show' button should display what's in the textbox
	push	40221c			; push lib name
	call	LoadLibraryA		; get handle of 'user32.dll'
	mov	edi, 4023a0		; put addr 4023a0 in EDI
	mov	dword ptr [edi], eax	; save lib handle for l8r use
	push	4023e0			; push func. name 'GetDlgItemTextA'
	push	dword ptr [edi]		; push it to the stack
	call	GetProcAddress		; get func. addr
	push	14			; max size of text to get '20'
	push	4023c3			; buffer addr
	push	3ea			; textbox ID
	push	dword ptr [ebp+8]	; dialog handle
	call	eax			; call GetDlgItemTextA
	test	eax, eax		; nothing entered?
	jz	402399			; then don't display a thing
	push	4023d4			; push func. name 'MessageBoxA'
	push	dword ptr [edi]		; push lib handle
	call	GetProcAddress		; and get the func. addr
	push	0			; msg type
	push	4023f0			; caption
	push	4023c3			; text
	push	0			; window handle
	call	eax			; call MessageBoxA
402399:
	jmp	401170			; go back to main procedure
بعد ان تقوم بكتابة هذا الترميز في Olly يمكنك نسخه مباشرة الى الملف التنفيذي دون الحاجة الى استخدام اي محرر لاجراء التعديلات المطلوبة.. لذا قم بتحديد ما قمت بكتابته بواسطة الماوس وانقر عليه زر يمين واختر Copy to executable -> Selection.. قم بالعودة الى نافذة الترميز الاصلي ومن ثم عد بواسطة النقر على زر - الى حيث قمت بتحويل مسار الفيض اي الى الامر JMP 402340 وقم بتغيير قيمة 2711 الى 3E9 ومن ثم قم بتحديد التغييرات تلك (اي تعليمة JMP والقيمة المعدلة) واختر Copy to executable -> All modifications. الان قم باغلاق النافذة الجديدة التي تظهر لك وسيتم سؤالك ان كنت تريد حفظ التغييرات لذا قم بالموافقة وقم بحفظ الملف بالاسم نفسه واستبدال الاصلي.. الا ان اردت ابقاء نسخة احتياطية.. الامر يعود لك.

قم باختبار التغييرات التي قمت بها لكن لسوء الحظ فان البرنامج يتم اغلاقه بسبب خطا فما السبب؟ السبب يعود الى ان الترميز الذي قمنا بادخاله يحاول حفظ بعض القيم في المقطع .rdata حيث يوجد لكن المقطع المذكور لا يحمل خاصة Write اي لا يسمح بالكتابة فيه وبالتالي قم باستخدام LordPE وقم بتغيير الـ characterstics الخاصة بالمقطع الى C0000040 وستكون قد انتهيت.. دعونا نامل ان يعمل تحت انظمة اخرى! p:


:In the end

(وبالانكليزية عشان الكل يفهم :)

I'de like to send my greetings to: Fusion members (some have been away for awhile, let's hope they're seeking more knowledge and to see 'em back to the crack soon), hav0k, Fenri (for his short notes about menu resourcing) and all r3^3r$3r$ in the world, may the tool be with you }:D

اي تعليقات او ملاحظات مرحب بها - Xacker of Fusion